module tamagawa_Encoder_read (
    input wire sys_rst_n,       //复位信号
    input wire clk,             //模块时钟
    output reg dir_flag,        //控制转接板发送接收
    input wire rx_data,         //编码器接收线
    output reg tx_data,         //编码器发送线
    output reg[47:0] data,      //处理完毕的数据
    output reg SPI_tx_flag      //用于标志SPI发送使能
);
//寄存器定义
reg tx_flag;
reg[7:0] tx_cnt;
reg[7:0] rx_cnt;
reg[111:0] databuffer;
reg rxd_d0;
reg rxd_d1;
reg rxd_d2;
reg rxd_d3;    
reg[7:0] timeout;
reg[10:0] CF_conmand=11'b10010110001;//编码器指令
reg rx_flag2;
reg crc_flag;
reg[7:0] crc_real;
reg[7:0] crc_cal;
reg crc_err;
reg[8:0] crc_cmp;
reg[8:0] crc_res;
reg[7:0] crc_cnt;

//线定义
wire rx_flag1;

//接收数据边沿监测检测到1001则拉高rx_flag1
assign rx_flag1 = rxd_d3&(~rxd_d2)&(~rxd_d1)&rxd_d0; 
//循环检测连续接收到的4个电平
always @(posedge clk or negedge sys_rst_n)
begin
    if(!sys_rst_n)
    begin
        rxd_d0<=1'b0;
        rxd_d1<=1'b0;
        rxd_d2<=1'b0;
        rxd_d3<=1'b0;
    end
    else begin
        rxd_d0<=rx_data;
        rxd_d1<=rxd_d0;
        rxd_d2<=rxd_d1;
        rxd_d3<=rxd_d2;
    end
end
//当rx_flag1被拉高，间隔一个时钟周期拉高rx_flag2，
//当rx_cnt==112时接收完毕拉低rx_flag2（当前指令下编码器每次返回110bit的数据）
always @(posedge clk or negedge sys_rst_n)
begin
    if(!sys_rst_n)
        rx_flag2<=1'b0;
    else begin
        if(rx_flag1==1&&dir_flag==0)//检测到rx_flag1拉高且方向为接收时拉高rx_flag2
            rx_flag2<=1'b1;
        else if(rx_cnt == 8'd112)   //接收完毕时拉低rx_flag2
            rx_flag2<=1'b0;
        else
            rx_flag2<=rx_flag2;     //保持flag状态
    end
end
//超时判断逻辑，超过255个时钟周期编码器没有数据返回，则再次发送指令
always @(posedge clk or negedge sys_rst_n)
begin
    if(!sys_rst_n)
        timeout<=8'd0;
    else begin
        if(tx_flag==0&&rx_flag2==0&&timeout<8'd255)
            timeout<=timeout+1;
        else if(rx_flag2==1||timeout==8'd255)
            timeout<=8'd0;
        else
            timeout<=timeout;
    end
end
            
        
        
//指令发送逻辑
always @(posedge clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
    tx_data <= 1;//不工作时高电平
    tx_cnt <= 8'd10;      
    end
    else if(tx_flag==1&&dir_flag==1) 
    begin
        tx_data<=CF_conmand[tx_cnt];
        if(tx_cnt==8'd0)
            tx_cnt<=8'd10;
        else
            tx_cnt<=tx_cnt-1;
    end
    else begin
        tx_data<=1;
    end
end
//方向控制逻辑
always @(posedge clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        dir_flag<=1;//不工作时高电平
    end
    else begin
        if(timeout==8'd20||timeout==255)
            dir_flag<=1;
        else if(tx_cnt==8'd0)
            dir_flag<=0;
        else
            dir_flag<=dir_flag;
    end
end
//数据接收逻辑
always @(posedge clk or negedge sys_rst_n) begin
    if(!sys_rst_n) 
    begin
       tx_flag <= 1;//初始状态使能发送
       databuffer<=112'b0;

       rx_cnt<=0;
       crc_flag<=1'b0;
       crc_real<=8'd0;
    end
    else 
    begin
        if(tx_cnt==8'd0)
            tx_flag<=1'b0;
        else 
        begin
            if(timeout==255)
                tx_flag<=1'b1;
            else
                tx_flag<=tx_flag;
        end
        if(rx_flag2) 
        begin
            if(rx_cnt<106)
                crc_real<=(crc_real<<1)|rxd_d0;//实时获取位流中的8位连续数据，cnt=106时得到crc接收值
            crc_flag<=1'b1;
            databuffer[rx_cnt]<=rxd_d0;//缓存时将位流反向
            if(rx_cnt==8'd112)
            begin
                databuffer<=112'b0;
                crc_real<=0;
                crc_flag<=0;
            end
            else
                rx_cnt<=rx_cnt+1;
        end
        else  
        begin
            if(timeout==8'd20)//再次发送指令前等待20个时钟周期
                tx_flag<=1'b1;
            rx_cnt<=0;
        end
    end
end

reg[22:0] position;
reg[15:0] turns;
reg[7:0]  encoder_error;
//待发送数据处理
always @(posedge clk or negedge sys_rst_n) 
begin
    if(!sys_rst_n)
    begin
        SPI_tx_flag<=0;
        position<=0;
        turns<=0;
        data<=0;
        encoder_error<=0;
    end
    else 
    begin
        if(rx_cnt==8'd108)
        begin
            position<={databuffer[44:38],databuffer[35:28],databuffer[25:18]};//从数据缓存中取出需要的数据
            turns<={databuffer[85:78],|databuffer[75:68],databuffer[65:58]};
            encoder_error<=databuffer[95:88];
        end
        else if(rx_cnt==8'd109) //将数据合并到data中
            data[47:25]<=position[22:0];
        else if(rx_cnt==8'd110)
            data[24:9]<=turns[15:0];
        else if(rx_cnt==8'd111)
            data[8:1]<=encoder_error[7:0];
        else if(rx_cnt==8'd112)
            begin 
            data[0]<=crc_err;
            SPI_tx_flag<=1;
            end   
        else
        begin
            SPI_tx_flag<=0;//发送结束
            position<=0;
            turns<=0;
            encoder_error<=0;
            data<=0;
        end
    end 
end
//CRC校验计算 多项式x^8+1 100000001
always @(posedge clk or negedge sys_rst_n) 
begin
    if(!sys_rst_n)
    begin
        crc_cmp<=9'b000000010;
        crc_res<=9'b100000001;
        crc_cal<=8'd0;
        crc_err<=1'b0;
        crc_cnt<=0;
    end
    else
    begin
        if(crc_flag)
        begin
            if(8'd108>rx_cnt)
            begin
                if(rx_cnt==(crc_cnt*10+6)&&crc_cnt<9)//跳过起始位和终止位
                    crc_cnt<=crc_cnt;
                else if(rx_cnt==(crc_cnt*10+7)&&crc_cnt<9)
                    crc_cnt<=crc_cnt+1;
                else
                begin 
                    if(rx_cnt<96)
                    begin
                        if(crc_cmp[8])//位流首位为1
                            crc_cmp<=((crc_res^crc_cmp)<<1)|rxd_d0;//异或
                        else
                            crc_cmp<=(crc_cmp<<1)|rxd_d0;
                    end
                    else
                    begin
                        if(crc_cmp[8])//位流首位为1
                            crc_cmp<=((crc_res^crc_cmp)<<1)|1'b0;//数据后面补0再异或
                        else
                            crc_cmp<=(crc_cmp<<1)|1'b0;
                    end
                end
                if(rx_cnt==8'd105)
                    crc_cal[7:0]<=crc_cmp[8:1];
                if(rx_cnt==8'd106)
                    crc_err<=(crc_real==crc_cal)?0:1;//判断CRC接收值和计算值是否相等
            end

            else 
            begin 
                crc_err<=crc_err;
                crc_res[8:0]<=9'b100000001;
            end
        end
        else
        begin
            crc_cnt<=0;
            crc_err<=crc_err;
            crc_cmp<=9'b000000010;
            crc_cal[7:0]<=0;
            crc_cal[7:0]<=0;
        end
    end 
end
      
endmodule
